package com.nx.platform.entry.controllers;

import com.nx.platform.entry.utility.*;
import com.nx.platform.openentry.contract.ICmdRouterService;
import com.nx.platform.openentry.entity.CmdRouterResponse;
import com.nx.platform.openentry.entity.CookieEntity;
import com.nx.platform.openentry.entity.ServiceHeaderEntity;
import com.nx.platform.openentry.entity.response.OpenEntryCmdDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * @author alex
 * @brief
 * @date 2020/3/29
 */
@Slf4j
@RestController
public class OpenEntryController {
    public static final String APPLICATION_JSON = "application/json";
    
    private static final String DOMAIN = "naixuejiaoyu.com";
    
    /**
     * 入口
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "/open/{module}/{command}", method = {RequestMethod.POST, RequestMethod.GET})
    public void entry(@PathVariable String module, @PathVariable String command, HttpServletRequest request, HttpServletResponse response) {
        long startTime = System.currentTimeMillis();
        
        String logStr = String.valueOf(request.getAttribute(Constant.LOG_STRING));
        String logId = String.valueOf(request.getAttribute(Constant.LOG_ID));
        
        StringBuilder logSb = new StringBuilder(350);
        logSb.append(logStr);
        
        String[] uriParams = StringUtils.split(request.getRequestURI(), "/");
        if (ArrayUtils.getLength(uriParams) < 3) {
            logSb.append(" desc=wrong_param_num respCode=2 ");
            log.info(logSb.toString());
            ResponseUtils.responseMethod(Constant.RESP_CODE_SERVER_ERROR, null, "错误的域名", request, response);
        }
        
        // 解析请求参数
        Map<String, String> requestParams = new HashMap<String, String>();
        if (StringUtils.isNotEmpty(request.getContentType()) && request.getContentType().contains(APPLICATION_JSON)) {
            try {
                BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
                StringBuilder strBuilder = new StringBuilder(300);
                String inputStr;
                while ((inputStr = streamReader.readLine()) != null) {
                    strBuilder.append(inputStr);
                }
                if (strBuilder.length() > 0) {
                    requestParams = CommonUtil.getGson().fromJson(strBuilder.toString(), Map.class);
                }
                
            } catch (Exception e) {
                logSb.append(" desc=process application-json parse error respCode=-1");
                log.error(logSb.toString(), e);
            }
            
        }
        // 解析beat.getRequest().getParameterMap().isEmpty()追加进requestParams
        Map<String, String> requestParamsTemp = RequestUtils.buildMapFromRequest(request);
        requestParams.putAll(requestParamsTemp);
        
        OpenEntryCmdDto commandConfig = EntryConfigHelper.getCommandConfig(module, command);
        // command不存在
        if (commandConfig == null) {
            log.info("{} desc=no_command_found respCode=403 ", logStr);
            ResponseUtils.responseMethod(Constant.RESP_CODE_SERVER_ERROR, null, "错误的域名", request, response);
        }
        
        // long uid = (Long)request.getAttribute(Constant.REQ_UID);
        
        ICmdRouterService service = EntryConfigHelper.getService(module);
        if (service == null) {
            logSb.append(" desc=noCorrespondingService respCode=2 ");
            log.info(logSb.toString());
            ResponseUtils.responseMethod(Constant.RESP_CODE_LEAK_PARAM, null, "请求参数错误", request, response);
        }
        
        ServiceHeaderEntity header = RequestUtils.buildHeader(request);
        header.setCmd(command);
        header.setLogStr(logStr);
        header.setLogId(Long.parseLong(logId));
        
        try {
            CmdRouterResponse cmdRouterRetEntity = service.process(header, requestParams);
            if (cmdRouterRetEntity != null) {
                processCookies(cmdRouterRetEntity, request, response);
                log.info("{} desc=process ret={}", logSb, cmdRouterRetEntity.getRetCode());
                if (0 == cmdRouterRetEntity.getRetCode()) {
                    // 默认0是success
                    ResponseUtils.buildResult(cmdRouterRetEntity, request, response);
                } else {
                    ResponseUtils.responseMethod(cmdRouterRetEntity.getRetCode(), null, cmdRouterRetEntity.getErrorMsg(), request, response);
                }
            }
        } catch (Exception e) {
            // 调用服务超时
            if (e instanceof TimeoutException || (e.getCause() != null && e.getCause() instanceof TimeoutException)) {
                log.error(logStr + " desc=process respCode=504 e=" + E2s.exception2String(e));
                ResponseUtils.responseMethod(Constant.RESP_CODE_SERVER_ERROR, null, "服务端超时错误", request, response);
            } else {
                log.error(logStr + " desc=process respCode=-10001 processCost=" + E2s.exception2String(e));
                ResponseUtils.responseMethod(Constant.RESP_CODE_SERVER_ERROR, null, "服务异常", request, response);
            }
        }
        log.info(logStr + " desc=process respCode=501 processCost=" + (System.currentTimeMillis() - startTime));
        ResponseUtils.responseMethod(Constant.RESP_CODE_SERVER_ERROR, null, "数据异常", request, response);
    }
    
    /**
     * 处理接口返回的cookie信息
     * @param cmdRouterRetEntity
     */
    private void processCookies(CmdRouterResponse cmdRouterRetEntity, HttpServletRequest request, HttpServletResponse response) {
        if (cmdRouterRetEntity.getCookieValue() != null && cmdRouterRetEntity.getCookieValue().size() > 0) {
            String defaultDomain = DOMAIN;
            for (CookieEntity cookie : cmdRouterRetEntity.getCookieValue()) {
                if (StringUtils.isNotEmpty(cookie.getName()) && StringUtils.isNotEmpty(cookie.getValue())) {
                    String domain = defaultDomain;
                    if (StringUtils.isNotBlank(cookie.getDomain())) {
                        domain = cookie.getDomain();
                    }
                    addOneCookieValue(response, domain, cookie.getName(), cookie.getValue(), cookie.getMaxAge());
                }
            }
        }
    }
    
    private static void addOneCookieValue(HttpServletResponse response, String domain, String name, String value, int maxAge) {
        // 刷新cookie
        Cookie cookie = new Cookie(name, value);
        cookie.setPath("/");
        cookie.setMaxAge(maxAge);
        cookie.setDomain(domain);
        response.addCookie(cookie);
    }
}
